package com.camus.verify.biz.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import com.camus.verify.algorithm.SubsetAlgorithmAssembler4BigDecimal;
import com.camus.verify.bo.MatchBO;
import com.camus.verify.bo.MatchParam;
import com.camus.verify.entity.VerifyTask;
import com.camus.verify.entity.VerifyTaskAp;
import com.camus.verify.entity.VerifyTaskInvoice;
import com.google.common.collect.Lists;

import cn.hutool.json.JSONUtil;

/**
 * 发票与台账一对多匹配
 * 
 * @author jie.deng
 *
 */
@Service
@Order(value = 3)
public class One2ManyMatchHandler extends AbstractMatchHandler {

	@Override
	public List<MatchBO> match(final VerifyTask task, final List<VerifyTaskInvoice> invoiceCandidateList,
			final List<VerifyTaskAp> apCandidateList) {
		// 结果列表
		List<MatchBO> resultList = new ArrayList<>();
		List<VerifyTaskInvoice> leftCandidateList = invoiceCandidateList.stream().filter(t -> t.getMatched() == 0)
				.collect(Collectors.toList());
		List<VerifyTaskAp> rightCandidateList = apCandidateList.stream().filter(t -> t.getMatched() == 0)
				.collect(Collectors.toList());
		if (CollectionUtils.isEmpty(leftCandidateList) || CollectionUtils.isEmpty(rightCandidateList)) {
			return resultList;
		}

		if (log.isInfoEnabled()) {
			log.info("一对多匹配,入参={}", JSONUtil.toJsonStr(MatchParam.of(task, leftCandidateList, rightCandidateList)));
		}
		Set<BigDecimal> unMatchedTargetSet = new HashSet<>();
		for (Iterator<VerifyTaskInvoice> leftIter = leftCandidateList.iterator(); leftIter.hasNext();) {
			// 选择一个发票
			VerifyTaskInvoice left = (VerifyTaskInvoice) leftIter.next();
			BigDecimal target = left.getPendingVerifyAmt();

			if (unMatchedTargetSet.contains(target)) {
				continue;
			}

			// 选择多个台账
			SubsetAlgorithmAssembler4BigDecimal<VerifyTaskAp> subsetAssembler = new SubsetAlgorithmAssembler4BigDecimal<>();
			List<VerifyTaskAp> rightChosenList = subsetAssembler.findSubset(rightCandidateList,
					VerifyTaskAp::getPendingVerifyAmt, target, tolerance);

			// 生成匹配结果
			if (CollectionUtils.isNotEmpty(rightChosenList)) {
				resultList.add(buildResultBO(task, Lists.newArrayList(left), rightChosenList));
				leftIter.remove();
				rightCandidateList.removeAll(rightChosenList);
				if (CollectionUtils.isEmpty(rightCandidateList)) {
					break;
				}
			} else {
				unMatchedTargetSet.add(target);
			}
		}

		if (log.isInfoEnabled()) {
			log.info("一对多匹配,返回值={}", JSONUtil.toJsonStr(resultList));
		}
		return resultList;
	}

	@Override
	public String getMatchHandlerName() {
		return "一对多匹配";
	}

}
